#include "window.h"
#include <vector>
#include <iostream>

#include "scaleDialog.h"
#include "rotateDialog.h"
#include "translateDialog.h"
#include "rayTestPanel.h"
#include "input.h"
#include "objectTreeItem.h"
#include "cuboidDialog.h"
#include "sphereDialog.h"
#include "cylinderDialog.h"
#include "coneDialog.h"
#include "operationDialog.h"
#include "defines/primitive.h"
#include "defines/operation.h"
#include "src/combinedObject.h"

Window::Window(){
	setWindowTitle(QString::fromUtf8("[MODELAGEM GEOMÉTRICA] CSG"));
    statusBar()->showMessage(tr(""));
    setUnifiedTitleAndToolBarOnMac(true);

	canvas = new GLWidget(this);
	setCentralWidget(canvas);


	tree = NULL;

	inOperation = false;
	imageDlg = new ImageDialog(this);
    connect(canvas->getScene(), SIGNAL(setLine(unsigned int, uchar *)), imageDlg, SLOT(updateImageLine(unsigned int, uchar *)));

	createWindow();
}

Window::~Window(){
	if(canvas) delete canvas;
    if(geometricOperationToolBar) delete geometricOperationToolBar;
    if(setOperationToolBar) delete setOperationToolBar;
    if(editObjectAct) delete editObjectAct;
    if(deleteObjectAct) delete deleteObjectAct;
    if(duplicateObjectAct) delete duplicateObjectAct;
    if(tree) delete tree;
}

void Window::testRaytracing(Ray _r){
    canvas->getScene()->testRaytracing(_r);
//    canvas->changeShowRayTest(true);
    rayTestViewAct->setChecked(true);
    canvas->updateGL();
}

void Window::changeRaytracingDepth(int _d){
    canvas->getScene()->changeDepth(_d);
}

void Window::startRendering(){
    //mandar criar uma imagem do tamanho correto
    //guardar e mostrar o dialog dela
    Camera *c = canvas->getScene()->getCamera();
    imageDlg->setImageSize(c->getM(), c->getN());
    imageDlg->show();

    //mandar renderizar na cena, e receber linha da imagem
    //fazer connect do dialog com a cena.
    canvas->getScene()->doRaytracing();
}

//void Window::updateImage(std::vector<double> _colors){
//
//}

void Window::changeSelection(){

//    std::cout <<"------Estaria mudando! seleção!" <<std::endl;
    if(inOperation) return;

//    std::cout <<"\t\tAntes de mudar!" <<std::endl;

    for(int i = 0; i < previousSelected.size(); i++){
        QTreeWidgetItem *item = previousSelected.at(i);
        ((ObjectTreeItem *)item)->select(false);
    }
    previousSelected.clear();

    QList<QTreeWidgetItem *> selected = tree->selectedItems();

    for(int i = 0; i < selected.size(); i++){
        QTreeWidgetItem *item = selected.at(i);
        ((ObjectTreeItem *)item)->select(true);
        previousSelected.push_back(item);
    }
    setOperationToolBar->setEnabled(selected.size() > 1);
    geometricOperationToolBar->setEnabled(selected.size() > 0);
    editObjectAct->setEnabled(selected.size() > 0);
    deleteObjectAct->setEnabled(selected.size() == 1);
    duplicateObjectAct->setEnabled(selected.size() == 1);

//    std::cout <<"\t\tMudou!" <<std::endl;
    canvas->updateGL();

}

void Window::newScene(){
    updateActions();
    tree->clear();
    Scene *s = canvas->newScene();
    cameraPanel->setCamera(s->getCamera());
    connect(s, SIGNAL(setLine(unsigned int, uchar *)), imageDlg, SLOT(updateImageLine(unsigned int, uchar *)));
    output.setFile(NULL);
}

int Window::addTreeItem(Object *_obj, QTreeWidgetItem *_item, bool _setId){
    if(_setId){
        _obj->setId(canvas->getScene()->nextObjectsID());
    }

    QTreeWidgetItem *newItem = new ObjectTreeItem(_item, _obj);

    if(!_obj->isPrimitive()){
        int currentMaxId, maxId = -1;
        for(unsigned int i = 0; i < ((CombinedObject *)_obj)->getObjectsSize(); i++){
            currentMaxId = addTreeItem(((CombinedObject *)_obj)->getObject(i), newItem, _setId);
            if(currentMaxId > maxId) maxId = currentMaxId;
        }
        return maxId;
    }else return _obj->getId();
}

int Window::updateObjects(std::vector<Object *> _objs){
    inOperation = true;
    QTreeWidgetItem *rootItem = tree->invisibleRootItem();

    bool setId = (canvas->getScene()->getObjectsSize() > 0);

    int currentMaxId, maxId = -1;
    for(unsigned int i = 0; i < _objs.size(); i++){
        Object *obj = _objs.at(i);
        canvas->getScene()->addObject(obj);

        currentMaxId = addTreeItem(obj, rootItem, setId);
        if(currentMaxId > maxId) maxId = currentMaxId;
    }

    inOperation = false;
    return maxId;
}

void Window::openObjects(){
    QString filename = QFileDialog::getOpenFileName(this, tr("Acrescentar objetos"), QDir::currentPath(),tr("Arquivo de cenas (*.obs)"));

    if (!filename.isNull()){
//        qDebug() << "abrindo: " << filename;
        QFile* file = new QFile(filename);

        Input input;
        int maxId = updateObjects(input.parseObjects(file));
        canvas->getScene()->setNextObjectsID(maxId);

        output.setFile(file);
	}
	updateActions();
//	updateTreesVolume(false);
}

void Window::openSceneObjects(){

    std::cout <<"Podia perguntar se a pessoa quer salvar o ultimo ou não" <<std::endl;

	QString filename = QFileDialog::getOpenFileName(this, tr("Abrir cena"), QDir::currentPath(),tr("Arquivo de cenas (*.obs)"));

    if (!filename.isNull()){
        newScene();
        qDebug() << "abrindo: " << filename;
        QFile* file = new QFile(filename);

        Input input;
        int maxId = updateObjects(input.parseObjects(file));
        canvas->getScene()->setNextObjectsID(maxId);

        output.setFile(file);
	}
	updateActions();
//	updateTreesVolume(false);

}

void Window::saveSceneObjects(){
    if(output.isFileNull()){
        if(!saveSceneObjectsAs()) return;
    }

    output.parseObjects(canvas->getScene());

    saveObjectsAct->setEnabled(false);
}

bool Window::saveSceneObjectsAs(){
	QString filename = QFileDialog::getSaveFileName(this, tr("Salvar objetos da cena como..."), QDir::currentPath(), tr("Arquivo de objetos (*.obs)"));

    if (filename.isNull()) return false;

    if (QFileInfo(filename).suffix().isEmpty())
        filename += ".obs";

    QFile* file = new QFile(filename);

	output.parseObjects(file, canvas->getScene());

    saveObjectsAct->setEnabled(false);

    return true;
}

void Window::editObjectDialog(QTreeWidgetItem * _item, int){
    _item->setSelected(false);
    inOperation = true;

    Object *obj = ((ObjectTreeItem *)_item)->getObject();
    if(obj->isPrimitive()){
        switch(obj->getType()){
            case CUBOID:{
                CuboidDialog *dlg = new CuboidDialog((CuboidPrimitive *)obj, (ObjectTreeItem *)_item, this);
                dlg->show();
                connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

                break;
            }
            case SPHERE:{
                SphereDialog *dlg = new SphereDialog((SpherePrimitive *)obj, (ObjectTreeItem *)_item, this);
                dlg->show();
                connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

                break;
            }
            case CYLINDER:{
                CylinderDialog *dlg = new CylinderDialog((CylinderPrimitive *)obj, (ObjectTreeItem *)_item, this);
                dlg->show();
                connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

                break;
            }
            case CONE:{
                ConeDialog *dlg = new ConeDialog((ConePrimitive *)obj, (ObjectTreeItem *)_item, this);
                dlg->show();
                connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

                break;
            }
        }
    }
    else{
        OperationDialog *dlg = new OperationDialog((CombinedObject *)obj, (ObjectTreeItem *)_item, tree->invisibleRootItem(), canvas->getScene(), this);
        dlg->show();
        connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

    }

    updateActions();

    inOperation = false;
}

void Window::duplicateObject(QTreeWidgetItem *_parent, Object *_obj){
    QTreeWidgetItem *item = new ObjectTreeItem(_parent, _obj);

    if(!_obj->isPrimitive()){
        for(unsigned int i = 0; i < ((CombinedObject *)_obj)->getObjectsSize(); i++){
            duplicateObject(item, ((CombinedObject *)_obj)->getObject(i));
        }
    }
}

Object *Window::duplicateObject(Object *_obj){

    Object *newObj = NULL;

    if(_obj->isPrimitive()){
        switch(_obj->getType()){
            case CUBOID:{
                newObj = new CuboidPrimitive((*((CuboidPrimitive *)_obj)), canvas->getScene()->nextObjectsID());
                break;
            }
            case SPHERE:{
                newObj = new SpherePrimitive((*((SpherePrimitive *)_obj)), canvas->getScene()->nextObjectsID());
                break;
            }
            case CYLINDER:{
                newObj = new CylinderPrimitive((*((CylinderPrimitive *)_obj)), canvas->getScene()->nextObjectsID());
                break;
            }
            case CONE:{
                newObj = new ConePrimitive((*((ConePrimitive *)_obj)), canvas->getScene()->nextObjectsID());
                break;
            }
        }
    }else{
        std::vector<Object *> newChildrens;
        for(unsigned int i = 0; i < ((CombinedObject *)_obj)->getObjectsSize(); i++){
            newChildrens.push_back( duplicateObject(((CombinedObject *)_obj)->getObject(i)) );
        }
        newObj = new CombinedObject((*((CombinedObject *)_obj)), newChildrens, canvas->getScene()->nextObjectsID());

    }

    return newObj;
}

void Window::duplicateObject(){
    QTreeWidgetItem *item = previousSelected.front();
    Object *obj = ((ObjectTreeItem *)item)->getObject();

    QTreeWidgetItem *parent = item->parent();

    Object *newObj = duplicateObject(obj);

    if(!parent){
        canvas->getScene()->addObject(newObj);
        parent = tree->invisibleRootItem();
    }else{
        Object *parentObject = ((ObjectTreeItem *)parent)->getObject();
        ((CombinedObject *)parentObject)->addObject(newObj);
    }

    duplicateObject(parent, newObj);

//    /*QTreeWidgetItem *newCuboidItem = */new ObjectTreeItem(parent, newObj);

}

void Window::deleteObject(){
    inOperation = true;
    for(int i = 0; i < previousSelected.size(); i++){
        QTreeWidgetItem *item = previousSelected.at(i);
        Object *obj = ((ObjectTreeItem *)item)->getObject();

        /*se o pai desse objeto não for o root,
        significa que ele eh uma composição,
        então tem que deletar esse objeto la também*/

        QTreeWidgetItem *parent = item->parent();
        if(parent == NULL){
            canvas->getScene()->deleteObject(obj);
            tree->invisibleRootItem()->removeChild(item);
        }
        else{
            Object *parentObj = (CombinedObject *)((ObjectTreeItem *)parent)->getObject();
            ((CombinedObject *)parentObj)->deleteObject(obj);
            parent->removeChild(item);

            if(parent->childCount() == 1){
                QTreeWidgetItem *otherItem = parent->child(0);
                parent->removeChild(otherItem);
                Object *otherItemObj = ((ObjectTreeItem *)otherItem)->getObject();

                QTreeWidgetItem *grandParent = parent->parent();
                if(grandParent == NULL){ //coloca na cena o objeto e na arvore principal
                    tree->invisibleRootItem()->addChild(otherItem);
                    canvas->getScene()->addObject(otherItemObj);

                    tree->invisibleRootItem()->removeChild(parent);
                    canvas->getScene()->deleteObject(parentObj);

                }else{
                    Object *grandParentObject = ((CombinedObject *)((ObjectTreeItem *)grandParent)->getObject());

                    grandParent->addChild(otherItem);
                    ((CombinedObject *)grandParentObject)->addObject(otherItemObj);

                    grandParent->removeChild(parent);
                    ((CombinedObject *)grandParentObject)->deleteObject(parentObj);

                    //atualiznado o pai mais acima
                    while(grandParent->parent() != NULL){
                        grandParent = grandParent->parent();
                    }

                }

                delete parent;
                delete parentObj;
            }
        }

        delete item;
        delete obj;


    }
    updateActions();

    canvas->updateGL();

    previousSelected.clear();
    inOperation = false;
}

void Window::addPrimitive(Object *_obj){
    inOperation = true;
    QTreeWidgetItem *rootItem = tree->invisibleRootItem();

    canvas->getScene()->addObject(_obj);
    /*QTreeWidgetItem *newCuboidItem = */new ObjectTreeItem(rootItem, _obj);

    updateActions();

    inOperation = false;
    canvas->updateGL();
}

void Window::newCuboidPrimitiveDialog(){
    CuboidDialog *dlg = new CuboidDialog(canvas->getScene()->nextObjectsID(), this);
    dlg->show();

    connect(dlg, SIGNAL(done(Object *)), this, SLOT(addPrimitive(Object *)));
}

void Window::newSpherePrimitiveDialog(){
    SphereDialog *dlg = new SphereDialog(canvas->getScene()->nextObjectsID(), this);
    dlg->show();

    connect(dlg, SIGNAL(done(Object *)), this, SLOT(addPrimitive(Object *)));
}

void Window::newCylinderPrimitiveDialog(){
    CylinderDialog *dlg = new CylinderDialog(canvas->getScene()->nextObjectsID(), this);
    dlg->show();

    connect(dlg, SIGNAL(done(Object *)), this, SLOT(addPrimitive(Object *)));
}

void Window::newConePrimitiveDialog(){
    ConeDialog *dlg = new ConeDialog(canvas->getScene()->nextObjectsID(), this);
    dlg->show();

    connect(dlg, SIGNAL(done(Object *)), this, SLOT(addPrimitive(Object *)));
}

std::vector<Object *> Window::preOperation(QTreeWidgetItem **parent){
    inOperation = true;


    *parent = previousSelected.at(0)->parent();
    std::vector<Object *> objects;
    objects.push_back(((ObjectTreeItem *)previousSelected.at(0))->getObject());

    for(int i = 1; i < previousSelected.size(); i++){
        QTreeWidgetItem *item = previousSelected.at(i);
        objects.push_back(((ObjectTreeItem *)item)->getObject());
        if(item->parent() != *parent) {
            inOperation = false;
            QMessageBox::information(this, QString::fromUtf8("Erro na operação"), QString::fromUtf8("Escolha objetos com o mesmo pai."));
            objects.clear();
            break;
        }
    }
    if(*parent){
        if((*parent)->childCount() == previousSelected.size()){
            inOperation = false;
            QMessageBox::information(this, QString::fromUtf8("Erro na operação"), QString::fromUtf8("Não se pode fazer uma operação com todos os filhos."));
            objects.clear();
        }
    }
    return objects;
}

void Window::postOperation(QTreeWidgetItem *_parent, Object *_obj){
    Object *parentObject = NULL;
    if(_parent == NULL){
        _parent = tree->invisibleRootItem();
        canvas->getScene()->addObject(_obj);
    }else{
        parentObject = ((ObjectTreeItem *)_parent)->getObject();
        ((CombinedObject *)parentObject)->addObject(_obj);
    }
    QTreeWidgetItem *newCombinedItem = new ObjectTreeItem(_parent, _obj);


    int size = previousSelected.size();
    for(int i = 0; i < size; i++){
        QTreeWidgetItem *item = previousSelected.at(i);
        Object *currentObj = ((ObjectTreeItem *)item)->getObject();
        currentObj->select(false);
        if(!parentObject){
            canvas->getScene()->deleteObject(currentObj);
        }else{
            ((CombinedObject *)parentObject)->deleteObject(currentObj);
        }


        _parent->removeChild(item);
        newCombinedItem->addChild(item);
        item->setExpanded(true);
    }


    previousSelected.clear();
    updateActions();
    inOperation = false;
    canvas->updateGL();
}

void Window::unionOperation(){
    QTreeWidgetItem *parent;
    std::vector<Object *> objects = preOperation(&parent);
    if(objects.empty()) return;

    postOperation(parent, new CombinedObject(UNION, objects, objects.at(0)->getMaterial(), canvas->getScene()->nextObjectsID()));
}

void Window::intersectionOperation(){
    QTreeWidgetItem *parent;
    std::vector<Object *> objects = preOperation(&parent);
    if(objects.empty()) return;

    postOperation(parent, new CombinedObject(INTERSECTION, objects, objects.at(0)->getMaterial(), canvas->getScene()->nextObjectsID()));
}

void Window::differenceOperation(){
    QTreeWidgetItem *parent;
    std::vector<Object *> objects = preOperation(&parent);
    if(objects.empty()) return;

    postOperation(parent, new CombinedObject(DIFFERENCE, objects, objects.at(0)->getMaterial(), canvas->getScene()->nextObjectsID()));
}

void Window::translateOperation(){
    TranslateDialog *dlg = new TranslateDialog(previousSelected, this);
    dlg->show();
    connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

    if(rayTestViewAct->isChecked()){
        rayTestViewAct->setChecked(false);
        canvas->getScene()->clearTestRay();
        canvas->updateGL();
    }
    updateActions();
}

void Window::rotateOperation(){
    RotateDialog *dlg = new RotateDialog(previousSelected, this);
    dlg->show();
    connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

    if(rayTestViewAct->isChecked()){
        rayTestViewAct->setChecked(false);
        canvas->getScene()->clearTestRay();
        canvas->updateGL();
    }
    updateActions();
}

void Window::scaleOperation(){
    ScaleDialog *dlg = new ScaleDialog(previousSelected, this);
    dlg->show();
    connect(dlg, SIGNAL(done()), canvas, SLOT(updateGL()));

    if(rayTestViewAct->isChecked()){
        rayTestViewAct->setChecked(false);
        canvas->getScene()->clearTestRay();
        canvas->updateGL();
    }
    updateActions();
}

void Window::createWindow(){

//    std::cout <<"Criando window" <<std::endl;

    //Criando paineis ----------------------------------------------------------
    QDockWidget *treePanelDock = new QDockWidget(tr("Objetos"), this);

    tree = new QTreeWidget(treePanelDock);
//    tree->setHeaderHidden(true);
    tree->setContextMenuPolicy(Qt::ActionsContextMenu);
    tree->setSelectionMode(QAbstractItemView::ExtendedSelection);
    tree->setSelectionBehavior(QAbstractItemView::SelectRows);
    tree->setAnimated(true);
    tree->setExpandsOnDoubleClick(false);



	treePanelDock->setWidget(tree);
    treePanelDock->setMaximumWidth(350);
//    treePanelDock->setMinimumHeight(200);
    addDockWidget(Qt::RightDockWidgetArea, treePanelDock);

    QTreeWidgetItem *headerItem = tree->headerItem();
    headerItem->setText(0, "Objetos");

    connect(tree, SIGNAL(itemSelectionChanged()), this, SLOT(changeSelection()));




    QDockWidget *rayTestDock = new QDockWidget(QString::fromUtf8("Teste de raio"), this);

    RayTestPanel *rayTestPanel = new RayTestPanel(rayTestDock);

	rayTestDock->setWidget(rayTestPanel);
    rayTestDock->setMaximumWidth(350);
    rayTestDock->setMaximumHeight(250);

    addDockWidget(Qt::RightDockWidgetArea, rayTestDock);

    connect(rayTestPanel, SIGNAL(test(Ray)), this, SLOT(testRaytracing(Ray)));





    QDockWidget *cameraPanelDock = new QDockWidget(QString::fromUtf8("Camera"), this);

    cameraPanel = new CameraPanel(cameraPanelDock, canvas->getScene()->getCamera());

	cameraPanelDock->setWidget(cameraPanel);
    cameraPanelDock->setMaximumWidth(350);

    addDockWidget(Qt::RightDockWidgetArea, cameraPanelDock);
    tabifyDockWidget(cameraPanelDock, rayTestDock);
    tabifyDockWidget(cameraPanelDock, treePanelDock);

    connect(cameraPanel, SIGNAL(update()), canvas, SLOT(updateGL()));






    //Criando ações ------------------------------------------------------------
    QAction *newSceneAct = new QAction(QString::fromUtf8("Nova Cena"), this);
    newSceneAct->setShortcuts(QKeySequence::New);
    newSceneAct->setStatusTip(QString::fromUtf8("Criar uma nava cena sem objetos."));
    connect(newSceneAct, SIGNAL(triggered()), this, SLOT(newScene()));

    QAction *openSceneObjectsAct = new QAction(QString::fromUtf8("Abrir cena"), this);
    openSceneObjectsAct->setShortcuts(QKeySequence::Open);
    openSceneObjectsAct->setStatusTip(QString::fromUtf8("Abrir uma nava cena de objetos."));
    connect(openSceneObjectsAct, SIGNAL(triggered()), this, SLOT(openSceneObjects()));

    QAction *openObjectsAct = new QAction(QString::fromUtf8("Abrir objetos"), this);
    openObjectsAct->setStatusTip(QString::fromUtf8("Abrir objetos na cena atual."));
    connect(openObjectsAct, SIGNAL(triggered()), this, SLOT(openObjects()));

    saveObjectsAct = new QAction(QString::fromUtf8("Salvar objetos"), this);
    saveObjectsAct->setShortcuts(QKeySequence::Save);
    saveObjectsAct->setStatusTip(QString::fromUtf8("Salvar objetos da cena atual."));
    saveObjectsAct->setEnabled(false);
    connect(saveObjectsAct, SIGNAL(triggered()), this, SLOT(saveSceneObjects()));

    QAction *saveObjectsAsAct = new QAction(QString::fromUtf8("Salvar objetos como..."), this);
    saveObjectsAsAct->setShortcuts(QKeySequence::SaveAs);
    saveObjectsAsAct->setStatusTip(QString::fromUtf8("Salvar objetos da cena atual em novo arquivo."));
    connect(saveObjectsAsAct, SIGNAL(triggered()), this, SLOT(saveSceneObjectsAs()));

    QAction *exitAct = new QAction(QString::fromUtf8("Sair"), this);
    exitAct->setShortcuts(QKeySequence::Quit);
    exitAct->setStatusTip(QString::fromUtf8("Sair da aplicação."));
    connect(exitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));

    QAction *showAxisAct = new QAction(QString::fromUtf8("Eixos"), this);
    showAxisAct->setCheckable(true);
    showAxisAct->setChecked(canvas->isShowingAxis());
    showAxisAct->setStatusTip(QString::fromUtf8("Mostrar eixos."));
    connect(showAxisAct, SIGNAL(toggled(bool)), canvas, SLOT(changeShowAxis(bool)));

    QAction *showGridAct = new QAction(QString::fromUtf8("Grade"), this);
    showGridAct->setCheckable(true);
    showGridAct->setChecked(canvas->isShowingGrid());
    showGridAct->setStatusTip(QString::fromUtf8("Mostrar grade."));
    connect(showGridAct, SIGNAL(toggled(bool)), canvas, SLOT(changeShowGrid(bool)));

	QAction *viewTreePanelAct = treePanelDock->toggleViewAction();

	QAction *viewRayTestPanelAct = rayTestDock->toggleViewAction();

	QAction *viewCameraPanelAct = cameraPanelDock->toggleViewAction();

    editObjectAct = new QAction(QString::fromUtf8("Modificar objeto"), this);
    editObjectAct->setStatusTip(QString::fromUtf8("Modifica os objetos selecionados"));
    editObjectAct->setDisabled(true);
//    connect(editObjectAct, SIGNAL(triggered()), this, SLOT(editObjectDialog()));
    connect(tree, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(editObjectDialog(QTreeWidgetItem *, int)));

    deleteObjectAct = new QAction(QString::fromUtf8("Remover objetos"), this);
    deleteObjectAct->setStatusTip(QString::fromUtf8("Remove os objetos selecionados"));
    deleteObjectAct->setDisabled(true);
    connect(deleteObjectAct, SIGNAL(triggered()), this, SLOT(deleteObject()));

    duplicateObjectAct = new QAction(QString::fromUtf8("Duplicar objeto"), this);
    duplicateObjectAct->setStatusTip(QString::fromUtf8("Duplicar objeto selecionado"));
    duplicateObjectAct->setDisabled(true);
    connect(duplicateObjectAct, SIGNAL(triggered()), this, SLOT(duplicateObject()));


    QAction *newCuboidAct = new QAction(QIcon("../bitmaps/cuboid.xpm"), QString::fromUtf8("Novo hexaedro"), this);
    newCuboidAct->setStatusTip(QString::fromUtf8("Cria um novo hexaedro, definido pelo seu ponto mínimo e máximo."));
    connect(newCuboidAct, SIGNAL(triggered()), this, SLOT(newCuboidPrimitiveDialog()));

    QAction *newSphereAct = new QAction(QIcon("../bitmaps/sphere.xpm"), QString::fromUtf8("Nova esfera"), this);
    newSphereAct->setStatusTip(QString::fromUtf8("Cria uma nova esfera, definida pelo centro e raio."));
    connect(newSphereAct, SIGNAL(triggered()), this, SLOT(newSpherePrimitiveDialog()));

    QAction *newCylinderAct = new QAction(QIcon("../bitmaps/cylinder.xpm"), QString::fromUtf8("Novo cilindro"), this);
    newCylinderAct->setStatusTip(QString::fromUtf8("Cria um novo cilindro, definido pelo centro, raio e altura."));
    connect(newCylinderAct, SIGNAL(triggered()), this, SLOT(newCylinderPrimitiveDialog()));

    QAction *newConeAct = new QAction(QIcon("../bitmaps/cone.xpm"), QString::fromUtf8("Novo cone"), this);
    newConeAct->setStatusTip(QString::fromUtf8("Cria um novo cone, definido pelo centro, raio e altura."));
    connect(newConeAct, SIGNAL(triggered()), this, SLOT(newConePrimitiveDialog()));

    QAction *unionAct = new QAction(QIcon("../bitmaps/union.xpm"), QString::fromUtf8("União"), this);
    unionAct->setStatusTip(QString::fromUtf8("Cria um objeto sendo a união de todos os selecionados."));
    connect(unionAct, SIGNAL(triggered()), this, SLOT(unionOperation()));

    QAction *intersectionAct = new QAction(QIcon("../bitmaps/intersection.xpm"), QString::fromUtf8("Interseção"), this);
    intersectionAct->setStatusTip(QString::fromUtf8("Cria um objeto sendo a interseção de todos os selecionados."));
    connect(intersectionAct, SIGNAL(triggered()), this, SLOT(intersectionOperation()));

    QAction *differenceAct = new QAction(QIcon("../bitmaps/difference.xpm"), QString::fromUtf8("Diferença"), this);
    differenceAct->setStatusTip(QString::fromUtf8("Cria um objeto sendo a diferença de todos os selecionados."));
    connect(differenceAct, SIGNAL(triggered()), this, SLOT(differenceOperation()));

    QAction *translateAct = new QAction(QIcon("../bitmaps/translate.xpm"), QString::fromUtf8("Translação"), this);
    translateAct->setStatusTip(QString::fromUtf8("Translada os objetos selecionados."));
    connect(translateAct, SIGNAL(triggered()), this, SLOT(translateOperation()));

    QAction *rotateAct = new QAction(QIcon("../bitmaps/rotate.xpm"), QString::fromUtf8("Rotação"), this);
    rotateAct->setStatusTip(QString::fromUtf8("Rotaciona os objetos selecionados."));
    connect(rotateAct, SIGNAL(triggered()), this, SLOT(rotateOperation()));

    QAction *scaleAct = new QAction(QIcon("../bitmaps/scale.xpm"), QString::fromUtf8("Escala"), this);
    scaleAct->setStatusTip(QString::fromUtf8("Escalona os objetos selecionados."));
    connect(scaleAct, SIGNAL(triggered()), this, SLOT(scaleOperation()));

    QAction *wireframeAct = new QAction(QIcon("../bitmaps/wireframe.xpm"), QString::fromUtf8("Wireframe"), this);
    wireframeAct->setStatusTip(QString::fromUtf8("Desenha os objetos em wireframe."));
    wireframeAct->setCheckable(true);
    connect(wireframeAct, SIGNAL(toggled(bool)), canvas, SLOT(changeObjectView(bool)));

    QAction *showCameraAct = new QAction(QIcon("../bitmaps/camera.xpm"), QString::fromUtf8("Camera"), this);
    showCameraAct->setStatusTip(QString::fromUtf8("Desenha plano focal."));
    showCameraAct->setCheckable(true);
    connect(showCameraAct, SIGNAL(toggled(bool)), canvas, SLOT(changeShowCamera(bool)));

    rayTestViewAct = new QAction(QIcon("../bitmaps/ray.xpm"), QString::fromUtf8("Raio de teste"), this);
    rayTestViewAct->setStatusTip(QString::fromUtf8("Mostra o raio que está sendo testado."));
    rayTestViewAct->setCheckable(true);
    connect(rayTestViewAct, SIGNAL(toggled(bool)), canvas, SLOT(changeShowRayTest(bool)));


    tree->addAction(deleteObjectAct);
    tree->addAction(duplicateObjectAct);

    //Criando toolbar ----------------------------------------------------------
    QToolBar *objectsToolBar = addToolBar(tr("Barra de primitivas"));
    objectsToolBar->addAction(newCuboidAct);
    objectsToolBar->addAction(newSphereAct);
    objectsToolBar->addAction(newCylinderAct);
    objectsToolBar->addAction(newConeAct);

    setOperationToolBar = addToolBar(QString::fromUtf8("Barra de operações de conjuntos"));
    setOperationToolBar->addAction(unionAct);
    setOperationToolBar->addAction(intersectionAct);
    setOperationToolBar->addAction(differenceAct);
    setOperationToolBar->setDisabled(true);

    geometricOperationToolBar = addToolBar(QString::fromUtf8("Barra de operações geométricas"));
    geometricOperationToolBar->addAction(translateAct);
    geometricOperationToolBar->addAction(rotateAct);
    geometricOperationToolBar->addAction(scaleAct);
    geometricOperationToolBar->setDisabled(true);



    QToolBar *wireframeToolBar = addToolBar(QString::fromUtf8("Barra de visualização"));
    wireframeToolBar->addAction(wireframeAct);
    wireframeToolBar->addAction(showCameraAct);
    wireframeToolBar->addAction(rayTestViewAct);



    QLabel *raytracingDepthLabel = new QLabel(QString("Profundidade: "));
    QSpinBox *raytracingDepthSpinBox = new QSpinBox;
    raytracingDepthSpinBox->setMinimum(1);
    raytracingDepthSpinBox->setMaximum(20);
    raytracingDepthSpinBox->setValue(3);
    connect(raytracingDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(changeRaytracingDepth(int)));

    QPushButton *renderPushButton = new QPushButton(tr("Renderizar"));
    connect(renderPushButton, SIGNAL(clicked()), this, SLOT(startRendering()));

    QToolBar *renderToolBar = addToolBar(QString::fromUtf8("Barra de renderização"));
    renderToolBar->addWidget(raytracingDepthLabel);
    renderToolBar->addWidget(raytracingDepthSpinBox);
    renderToolBar->addWidget(renderPushButton);

	QAction *veiwObjectsToolBarAct = objectsToolBar->toggleViewAction();
	QAction *veiwSetOperationToolBarAct = setOperationToolBar->toggleViewAction();
	QAction *veiwGeometricOperationToolBarAct = geometricOperationToolBar->toggleViewAction();
	QAction *veiwRenderToolBarAct = renderToolBar->toggleViewAction();
	QAction *viewWireframeToolBarAct = wireframeToolBar->toggleViewAction();

    //Criando menus ------------------------------------------------------------
    QMenu *fileMenu;
    QMenu *editMenu;
    QMenu *viewMenu;

    fileMenu = menuBar()->addMenu(QString::fromUtf8("&Arquivo"));
    fileMenu->addAction(newSceneAct);
    fileMenu->addSeparator();
    fileMenu->addAction(openObjectsAct);
    fileMenu->addAction(openSceneObjectsAct);
    fileMenu->addSeparator();
    fileMenu->addAction(saveObjectsAct);
    fileMenu->addAction(saveObjectsAsAct);
    fileMenu->addSeparator();
    fileMenu->addAction(exitAct);

    viewMenu = menuBar()->addMenu(QString::fromUtf8("&Visualizar"));
    viewMenu->addAction(showAxisAct);
    viewMenu->addAction(showGridAct);
    viewMenu->addSeparator();
    viewMenu->addAction(viewTreePanelAct);
    viewMenu->addAction(viewRayTestPanelAct);
    viewMenu->addAction(viewCameraPanelAct);
    viewMenu->addSeparator();
    viewMenu->addAction(veiwObjectsToolBarAct);
    viewMenu->addAction(veiwSetOperationToolBarAct);
    viewMenu->addAction(veiwGeometricOperationToolBarAct);
    viewMenu->addAction(viewWireframeToolBarAct);
    viewMenu->addAction(veiwRenderToolBarAct);



    editMenu = menuBar()->addMenu(QString::fromUtf8("&Editar"));
    editMenu->addAction(editObjectAct);
    editMenu->addAction(deleteObjectAct);
    editMenu->addAction(duplicateObjectAct);
    editMenu->addSeparator();
}

void Window::updateActions(){
    QTreeWidgetItem *rootItem = tree->invisibleRootItem();
    double count = rootItem->childCount();

    setOperationToolBar->setDisabled(previousSelected.size()<2);
    geometricOperationToolBar->setDisabled(previousSelected.size()<1);
    deleteObjectAct->setEnabled(count == 1);
    duplicateObjectAct->setEnabled(count == 1);
    saveObjectsAct->setEnabled(true);

    if(rayTestViewAct->isChecked()){
        rayTestViewAct->setChecked(false);
        canvas->getScene()->clearTestRay();
        canvas->updateGL();
    }
}
